unit uSBD_Crypto_Codec;
{
Copyright 2009 Sean B. Durkin

This file is part of SBD Crypto Library.
SBD Crypto Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

SBD Crypto Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the Lesser GNU General Public License
along with SBD Crypto Library.  If not, see <http://www.gnu.org/licenses/>.
}
interface
uses Classes, uSBD_Crypto_StreamCipher, uSBD_Crypto_BlockCipher,
     uSBD_Crypto_BaseNonVisualComponent, uSBD_Crypto_CryptographicLibrary,
     uSBD_Crypto_Hash;

const
Default_SaltBytes = 8;
Max_SaltBytes = 255;

type
TCodecMode = (cmUnitialized, cmIdle, cmEncrypting, cmDecrypting);

TOnEncDecProgress = function ( Sender: TObject; CountBytesProcessed: int64): boolean of object;

ICodec = interface
  ['{721D22EB-66C7-45B7-B926-D7E5C964AED8}']
    procedure SetStreamCipher( const Value: IStreamCipher);
    procedure SetBlockCipher ( const Value: IBlockCipher);
    procedure SetChainMode   ( const Value: IBlockChainingModel);
    function  GetMode: TCodecMode;
    function  GetStreamCipher: IStreamCipher;
    function  GetBlockCipher : IBlockCipher;
    function  GetChainMode   : IBlockChainingModel;
    function  GetOnProgress  : TOnEncDecProgress;
    procedure SetOnProgress( Value: TOnEncDecProgress);
    function  GetSaltBytes: integer;
    procedure SetSaltBytes( Value: integer);

    procedure Init( const Key: string);
    procedure Reset;
    procedure Burn;

    procedure EncryptMemory( const Plaintext{in}; PlaintextLen: integer; CipherText{out}: TStream);
    procedure End_EncryptMemory;

    procedure DecryptMemory( Plaintext{out}: TStream; const CipherText{in}; CiphertextLen: integer);
    procedure End_DecryptMemory;

    procedure EncryptStream( Plaintext, CipherText: TStream);
    procedure DecryptStream( Plaintext, CipherText: TStream);

    procedure EncryptFile( const Plaintext_FileName, CipherText_FileName: string);
    procedure DecryptFile( const Plaintext_FileName, CipherText_FileName: string);

    procedure EncryptString( const Plaintext: string; var CipherText_Base64: ansistring);
    procedure DecryptString( var Plaintext: string; const CipherText_Base64: ansistring);

    procedure EncryptAnsiString( const Plaintext: ansistring; var CipherText_Base64: ansistring);
    procedure DecryptAnsiString( var Plaintext: ansistring; const CipherText_Base64: ansistring);

    function  SelfTest: boolean;

    property  Mode: TCodecMode                   read GetMode;
    property  StreamCipher: IStreamCipher        read GetStreamCipher write SetStreamCipher;
    property  BlockCipher : IBlockCipher         read GetBlockCipher  write SetBlockCipher;
    property  ChainMode   : IBlockChainingModel  read GetChainMode    write SetChainMode;
    property  SaltBytes   : integer              read GetSaltBytes    write SetSaltBytes;
    property  OnProgress  : TOnEncDecProgress    read GetonProgress   write SetOnProgress;
  end;




TSimpleCodec = class( TInterfacedPersistent, ICodec, IBlockCipherSelector)
  private
    FMode: TCodecMode;
    FStreamCipher: IStreamCipher;
    FParameterizedStreamCipher: IStreamCipher;
    FBlockCipher : IBlockCipher;
    FChainMode   : IBlockChainingModel;
    FOnProgress  : TOnEncDecProgress;

    FKey: TSymetricKey;
    FEnc: IStreamEncryptor;
    FDec: IStreamDecryptor;
    FMax_EncryptPlainText_FragmentSize : integer;
    FMax_DecryptCipherText_FragmentSize: integer;
    FPasswordHasher: IHash;
    FPlaintextCount, FCiphertextCount: int64;
    FProgressCount: integer;
    FSaltBytes: integer;
    FDesaltingStream: TStream;

    procedure SetStreamCipher( const Value: IStreamCipher);
    procedure SetBlockCipher ( const Value: IBlockCipher);
    procedure SetChainMode   ( const Value: IBlockChainingModel);
    function  GetMode: TCodecMode;
    function  GetStreamCipher: IStreamCipher;
    function  GetBlockCipher : IBlockCipher;
    function  GetChainMode   : IBlockChainingModel;
    function  GetOnProgress  : TOnEncDecProgress;
    procedure SetOnProgress( Value: TOnEncDecProgress);
    procedure ChangedCipher;
    function  GetSaltBytes: integer;
    procedure SetSaltBytes( Value: integer);

  public
    constructor Create;
    destructor  Destroy; override;

    procedure Init( const Key: string);
    procedure Reset;
    procedure Burn;

    procedure EncryptMemory( const Plaintext; PlaintextLen: integer; CipherText: TStream);
    procedure End_EncryptMemory;

    procedure DecryptMemory( Plaintext{out}: TStream; const CipherText{in}; CiphertextLen: integer);
    procedure End_DecryptMemory;

    procedure EncryptStream( Plaintext, CipherText: TStream);
    procedure DecryptStream( Plaintext, CipherText: TStream);

    procedure EncryptFile( const Plaintext_FileName, CipherText_FileName: string);
    procedure DecryptFile( const Plaintext_FileName, CipherText_FileName: string);

    procedure EncryptString( const Plaintext: string; var CipherText_Base64: ansistring);
    procedure DecryptString( var Plaintext: string; const CipherText_Base64: ansistring);

    procedure EncryptAnsiString( const Plaintext: ansistring; var CipherText_Base64: ansistring);
    procedure DecryptAnsiString( var Plaintext: ansistring; const CipherText_Base64: ansistring);

    function  SelfTest: boolean;

    property  Mode: TCodecMode                   read GetMode;
    property  StreamCipher: IStreamCipher        read GetStreamCipher write SetStreamCipher;
    property  BlockCipher : IBlockCipher         read GetBlockCipher  write SetBlockCipher;
    property  ChainMode   : IBlockChainingModel  read GetChainMode    write SetChainMode;
    property  SaltBytes   : integer              read GetSaltBytes    write SetSaltBytes;
    property  OnProgress  : TOnEncDecProgress    read GetonProgress   write SetOnProgress;
  end;


TCodec = class( TSBD_Crypto_BaseNonVisualComponent, ICodec, IBlockCipherSelector)
  private
    FCodec: TSimpleCodec;
    FLib: TCryptographicLibrary;

    procedure SetStreamCipher( const Value: IStreamCipher);
    procedure SetBlockCipher ( const Value: IBlockCipher);
    procedure SetChainMode   ( const Value: IBlockChainingModel);
    function  GetMode: TCodecMode;
    function  GetStreamCipher: IStreamCipher;
    function  GetBlockCipher : IBlockCipher;
    function  GetChainMode   : IBlockChainingModel;
    procedure SetStreamCipherId( const Value: string);
    procedure SetBlockCipherId ( const Value: string);
    procedure SetChainModeId   ( const Value: string);
    function  GetStreamCipherId: string;
    function  GetBlockCipherId : string;
    function  GetChainModeId   : string;
    function  GetOnProgress  : TOnEncDecProgress;
    procedure SetOnProgress( Value: TOnEncDecProgress);
    function  GetSaltBytes: integer;
    procedure SetSaltBytes( Value: integer);

    procedure StreamCipher_ReaderProc( Reader: TReader);
    procedure StreamCipher_WriterProc( Writer: TWriter);
    procedure BlockCipher_ReaderProc ( Reader: TReader);
    procedure BlockCipher_WriterProc ( Writer: TWriter);
    procedure ChainMode_ReaderProc   ( Reader: TReader);
    procedure ChainMode_WriterProc   ( Writer: TWriter);
    procedure SetLib( Value: TCryptographicLibrary);

  protected
    procedure Notification(
      AComponent: TComponent; Operation: TOperation); override;
    procedure Loaded; override;
    procedure DefineProperties( Filer: TFiler); override;

  public
    constructor Create( AOwner: TComponent); override;
    destructor  Destroy; override;

    procedure Init( const Key: string);
    procedure Reset;
    procedure Burn;

    procedure EncryptMemory( const Plaintext; PlaintextLen: integer; CipherText: TStream);
    procedure End_EncryptMemory;

    procedure DecryptMemory( Plaintext{out}: TStream; const CipherText{in}; CiphertextLen: integer);
    procedure End_DecryptMemory;

    procedure EncryptStream( Plaintext, CipherText: TStream);
    procedure DecryptStream( Plaintext, CipherText: TStream);

    procedure EncryptFile( const Plaintext_FileName, CipherText_FileName: string);
    procedure DecryptFile( const Plaintext_FileName, CipherText_FileName: string);

    procedure EncryptString( const Plaintext: string; var CipherText_Base64: ansistring);
    procedure DecryptString( var Plaintext: string; const CipherText_Base64: ansistring);

    procedure EncryptAnsiString( const Plaintext: ansistring; var CipherText_Base64: ansistring);
    procedure DecryptAnsiString( var Plaintext: ansistring; const CipherText_Base64: ansistring);

    property  Mode: TCodecMode                       read GetMode;
    property  StreamCipherIntf: IStreamCipher        read GetStreamCipher write SetStreamCipher;
    property  BlockCipherIntf : IBlockCipher         read GetBlockCipher  write SetBlockCipher;
    property  ChainModeIntf   : IBlockChainingModel  read GetChainMode    write SetChainMode;

    function  SelfTest: boolean;

    // ProgIds
    property  StreamCipherId: string      read GetStreamCipherId write SetStreamCipherId;
    property  BlockCipherId : string      read GetBlockCipherId  write SetBlockCipherId;
    property  ChainModeId   : string      read GetChainModeId    write SetChainModeId;

  published
    property  SaltBytes   : integer              read GetSaltBytes    write SetSaltBytes;
    property  CryptoLibrary: TCryptographicLibrary    read FLib write SetLib;
    property  OnProgress  : TOnEncDecProgress    read GetonProgress   write SetOnProgress;
  end;















implementation






uses SysUtils, Math, uStreamUtils;


type
TDesaltingStream = class( TStream)
  private
    FSaltBytes: integer;
    FFeeder: TStream;

  protected
    function  GetSize: int64; override;
    procedure SetSize( const NewSize: int64); overload; override;

  public
    function  Read( var Buffer; Count: Longint): Longint; override;
    function  Write( const Buffer; Count: Longint): Longint; override;
    function  Seek( const Offset: Int64; Origin: TSeekOrigin): int64; overload; override;

  public
    constructor Create( SaltBytes1: integer; Feeder1: TStream);
  end;



{ TSimpleCodec }

constructor TSimpleCodec.Create;
begin
FMode := cmUnitialized;
FStreamCipher := nil;
FParameterizedStreamCipher := nil;
FBlockCipher  := nil;
FChainMode    := nil;
FOnProgress   := nil;
FKey := nil;
FEnc := nil;
FDec := nil;
FMax_EncryptPlainText_FragmentSize  := -1;
FMax_DecryptCipherText_FragmentSize := -1;
FPlaintextCount := 0;
FProgressCount := 0;
FSaltBytes := Default_SaltBytes;
FDesaltingStream := nil;
// FPasswordHasher := blab bla
end;


destructor TSimpleCodec.Destroy;
begin
Burn;
FKey.Free;
inherited;
end;

procedure TSimpleCodec.Init( const Key: string);
var
  Seed, PWord: TMemoryStream;
  Hasher: IHasher;
  L, Diff, Amt: integer;
begin
if not assigned( FParameterizedStreamCipher) then
  raise Exception.Create( 'TSimpleCodec.Init - No cipher set.');
if Key = '' then
  raise Exception.Create( 'TSimpleCodec.Init - No password.');
if not assigned( FPasswordHasher) then
  raise Exception.Create( 'TSimpleCodec.Init - No hash set.');
if FMode in [cmEncrypting, cmDecrypting] then
  Reset;
FMode := cmUnitialized;
FPlaintextCount := 0;
FProgressCount  := 0;
FreeAndNil( FKey);
Seed  := TMemoryStream.Create;
PWord := TMemoryStream.Create;
try
  PWord.Write( Key[1], Length( Key) * SizeOf( Char));
  Hasher := FPasswordHasher.MakeHasher( self);
  Hasher.Update( PWord);
  Hasher.End_Hash( Seed);
  L := Seed.Size;
  if L = 0 then
    raise Exception.Create( 'TSimpleCodec.Init - Hash failed.');
  Diff := L - FParameterizedStreamCipher.SeedByteSize;
  if Diff > 0 then
      // Truncate
      Seed.Size := FParameterizedStreamCipher.SeedByteSize

    else if Diff < 0 then
      begin // Extend by repitition.
      Seed.Seek( 0, soEnd);
      Diff := - Diff;
      repeat
        Amt := Min( Diff, L);
        Seed.Write( Seed.Memory^, Amt);
        Dec( Diff, Amt)
      until Diff <= 0
      end;
  FKey := FParameterizedStreamCipher.GenerateKey( Seed)
finally
  Hasher.Burn;
  BurnMemoryStream( Seed);
  BurnMemoryStream( PWord);
  Seed.Free;
  PWord.Free
end;
FMax_EncryptPlainText_FragmentSize  := FParameterizedStreamCipher.Max_EncryptPlainText_FragmentSize;
FMax_DecryptCipherText_FragmentSize := FParameterizedStreamCipher.Max_DecryptCipherText_FragmentSize;
FMode := cmIdle
end;


procedure TSimpleCodec.ChangedCipher;
begin
if assigned( FStreamCipher) then
    begin
    FParameterizedStreamCipher := FStreamCipher.Parameterize( self);
    if not assigned( FParameterizedStreamCipher) then
      FParameterizedStreamCipher := FStreamCipher
    end
  else
    FParameterizedStreamCipher := nil;
if assigned( FParameterizedStreamCipher) then
    begin
    FMax_EncryptPlainText_FragmentSize  := FParameterizedStreamCipher.Max_EncryptPlainText_FragmentSize;
    FMax_DecryptCipherText_FragmentSize := FParameterizedStreamCipher.Max_DecryptCipherText_FragmentSize
    end
 else
    begin
    FMax_EncryptPlainText_FragmentSize  := -1;
    FMax_DecryptCipherText_FragmentSize := -1
    end
end;


procedure TSimpleCodec.Reset;
begin
if FMode = cmUnitialized then
  raise Exception.Create( 'TSimpleCodec.Init - Reset when not intialized.');
FreeAndNil( FDesaltingStream);
ChangedCipher;
FProgressCount := 0;
FEnc := nil;
FDec := nil;
FMode := cmIdle
end;


procedure TSimpleCodec.Burn;
begin
if FMode <> cmUnitialized then
  Reset;
FPlaintextCount := 0;
FProgressCount  := 0;
FreeAndNil( FKey);
FMode := cmUnitialized
end;

procedure TSimpleCodec.DecryptAnsiString(
  var Plaintext: ansistring;
  const CipherText_Base64: ansistring);
var
  Buffer: TStream;
  Ciphertext: ansistring;
begin
Ciphertext := CipherText_Base64;
Buffer := TMemoryStream.Create;
try
  if Ciphertext <> '' then
    DecryptMemory( Buffer, Ciphertext[1], Length( Ciphertext) * SizeOf( AnsiChar));
  End_DecryptMemory;
  Buffer.Position := 0;
  SetLength( Plaintext, Buffer.Size div SizeOf( AnsiChar));
  if Length( Plaintext) > 0 then
    Buffer.Read( Plaintext[1], Length( Plaintext) * SizeOf( AnsiChar))
finally
Buffer.Free
end;
end;



procedure TSimpleCodec.DecryptFile(
  const Plaintext_FileName,
  CipherText_FileName: string);
var
  plaintext, ciphertext: TStream;
begin
plaintext  := TFileStream.Create( Plaintext_FileName, fmCreate);
Ciphertext := TFileStream.Create( Ciphertext_FileName, fmOpenRead);
try
  DecryptStream( plaintext, ciphertext)
finally
  PlainText.Free;
  CipherText.Free
end end;


const BytesToCallBackProgress = 1024;


procedure TSimpleCodec.DecryptMemory(
  Plaintext{out}: TStream; const CipherText{in}; CiphertextLen: integer);
var
  C: PByte;
  L, Amt, M: integer;
  Buffer, OutputStream: TStream;
begin
if FMode = cmUnitialized then
  raise Exception.Create( 'TSimpleCodec.DecryptMemory - Cannot set enc/decrypt when not initialized.');
if FMode = cmEncrypting then
  raise Exception.Create( 'TSimpleCodec.DecryptMemory - Cannot decrypt whilst encrypting.');
if FMode = cmIdle then
  begin
  FCiphertextCount := 0;
  FProgressCount  := 0;
  FMode := cmDecrypting;
  FDesaltingStream.Free;
  if FSaltBytes > 0 then
      begin
      FDesaltingStream := TDesaltingStream.Create( FSaltBytes, Plaintext);
      OutputStream     := FDesaltingStream
      end
    else
      begin
      FDesaltingStream := nil;
      OutputStream     := PlainText
      end;
  FDec  := FParameterizedStreamCipher.Start_Decrypt( FKey, OutputStream);
  end;
C := @CipherText;
L := CipherTextLen;
M := FMax_DecryptCipherText_FragmentSize;
if M <= 0 then
  M := 512;
Buffer := TMemoryStream.Create;
while L > 0 do
  begin
  Amt := Min( L, M);
  Buffer.Size     := Amt;
  Buffer.Position := 0;
  Buffer.Write( C^, Amt);
  FDec.Decrypt( Buffer);
  Dec( L, Amt);
  Inc( C, Amt);
  Inc( FCiphertextCount, Amt);
  Inc( FProgressCount, Amt);
  if FProgressCount >= BytesToCallBackProgress then
    begin
    FProgressCount := 0;
    if assigned( FOnProgress) then
      FOnProgress( self, FPlaintextCount)
    end
  end
end;


procedure TSimpleCodec.DecryptStream( Plaintext, CipherText: TStream);
var
  Buffer: packed array[ 0.. 1023] of byte;
  L, Amt: integer;
begin
PlainText.Position := 0;
L := SizeOf( Buffer);
try
repeat
  Amt := Ciphertext.Read( Buffer, L);
  if Amt > 0 then
    DecryptMemory( CipherText, Buffer, Amt);
until Amt <> L;
finally
End_DecryptMemory
end end;


procedure TSimpleCodec.DecryptString(
  var Plaintext: string;
  const CipherText_Base64: ansistring);
var
  Buffer: TStream;
  Ciphertext: string;
begin
Ciphertext := CipherText_Base64;
Buffer := TMemoryStream.Create;
try
  if Plaintext <> '' then
    DecryptMemory( Buffer, Ciphertext[1], Length( Plaintext) * SizeOf( Char));
  End_DecryptMemory;
  Buffer.Position := 0;
  SetLength( Plaintext, Buffer.Size div SizeOf( Char));
  if Length( Plaintext) > 0 then
    Buffer.Read( Plaintext[1], Length( Plaintext) * SizeOf( Char))
finally
Buffer.Free
end;
end;


procedure TSimpleCodec.EncryptAnsiString(
  const Plaintext: ansistring;
  var CipherText_Base64: ansistring);
var
  Buffer: TStream;
  Ciphertext: ansistring;
begin
Buffer := TMemoryStream.Create;
try
  if Plaintext <> '' then
    EncryptMemory( Plaintext[1], Length( Plaintext) * SizeOf( AnsiChar), Buffer);
  End_EncryptMemory;
  Buffer.Position := 0;
  SetLength( Ciphertext, Buffer.Size div SizeOf( AnsiChar));
  if Length( Ciphertext) > 0 then
    Buffer.Read( Ciphertext[1], Length( Ciphertext) * SizeOf( AnsiChar))
finally
Buffer.Free
end;
CipherText_Base64 := Ciphertext
end;

procedure TSimpleCodec.EncryptFile(
  const Plaintext_FileName,
  CipherText_FileName: string);
var
  plaintext, ciphertext: TStream;
begin
plaintext  := TFileStream.Create( Plaintext_FileName, fmOpenRead);
Ciphertext := TFileStream.Create( Ciphertext_FileName, fmCreate);
try
  EncryptStream( plaintext, ciphertext)
finally
  PlainText.Free;
  CipherText.Free
end end;



procedure TSimpleCodec.EncryptMemory(
  const Plaintext; PlaintextLen: integer;
  CipherText: TStream);
var
  P: PByte;
  L, Amt, M: integer;
  Buffer: TMemoryStream;
begin
if FMode = cmUnitialized then
  raise Exception.Create( 'TSimpleCodec.EncryptMemory - Cannot set enc/decrypt when not initialized.');
if FMode = cmDecrypting then
  raise Exception.Create( 'TSimpleCodec.EncryptMemory - Cannot set encrypt whilst decrypting.');
if FMode = cmIdle then
  begin
  FPlaintextCount := 0;
  FProgressCount  := 0;
  FEnc  := FParameterizedStreamCipher.Start_Encrypt( FKey, CipherText);
  FMode := cmEncrypting
  end;
P := @Plaintext;
L := PlaintextLen;
M := FMax_EncryptPlainText_FragmentSize;
if M <= 0 then
  M := 512;
Buffer := TMemoryStream.Create;
try
if (L > 0) and (FPlaintextCount = 0) and (FSaltBytes > 0) then
  begin
  Buffer.Size := FSaltBytes;
  RandomFillStream( Buffer);
  FEnc.Encrypt( Buffer)
  end;
while L > 0 do
  begin
  Amt := Min( L, M);
  Buffer.Size     := Amt;
  Buffer.Position := 0;
  Buffer.Write( P^, Amt);
  FEnc.Encrypt( Buffer);
  Dec( L, Amt);
  Inc( P, Amt);
  Inc( FPlaintextCount, Amt);
  Inc( FProgressCount, Amt);
  if FProgressCount >= BytesToCallBackProgress then
    begin
    FProgressCount := 0;
    if assigned( FOnProgress) then
      FOnProgress( self, FPlaintextCount)
    end
  end
finally
  Buffer.Free
end end;


procedure TSimpleCodec.EncryptStream( Plaintext, CipherText: TStream);
var
  Buffer: packed array[ 0.. 1023] of byte;
  L, Amt: integer;
begin
PlainText.Position := 0;
L := SizeOf( Buffer);
try
repeat
  Amt := Plaintext.Read( Buffer, L);
  if Amt > 0 then
    EncryptMemory( Buffer, Amt, CipherText);
until Amt <> L;
finally
End_EncryptMemory
end end;


procedure TSimpleCodec.EncryptString(
  const Plaintext: string;
  var CipherText_Base64: ansistring);
var
  Buffer: TStream;
  Ciphertext: string;
begin
Buffer := TMemoryStream.Create;
try
  if Plaintext <> '' then
    EncryptMemory( Plaintext[1], Length( Plaintext) * SizeOf( Char), Buffer);
  End_EncryptMemory;
  Buffer.Position := 0;
  SetLength( Ciphertext, Buffer.Size div SizeOf( Char));
  if Length( Ciphertext) > 0 then
    Buffer.Read( Ciphertext[1], Length( Ciphertext) * SizeOf( Char))
finally
Buffer.Free
end;
CipherText_Base64 := Ciphertext
end;



procedure TSimpleCodec.End_DecryptMemory;
begin
case FMode of
  cmIdle:       begin end;

  cmDecrypting: begin
                FDec.End_Decrypt;
                Reset
                end;

  cmUnitialized,
  cmEncrypting:
  raise Exception.Create( 'TSimpleCodec.End_DecryptMemory - Wrong mode.');
  end
end;


procedure TSimpleCodec.End_EncryptMemory;
begin
case FMode of
  cmIdle:       begin end;

  cmEncrypting: begin
                FEnc.End_Encrypt;
                Reset
                end;

  cmUnitialized,
  cmDecrypting:
  raise Exception.Create( 'TSimpleCodec.End_EncryptMemory - Wrong mode.');
  end
end;



function TSimpleCodec.GetBlockCipher: IBlockCipher;
begin
result := FBlockCipher
end;

function TSimpleCodec.GetChainMode: IBlockChainingModel;
begin
result := FChainMode
end;

function TSimpleCodec.GetMode: TCodecMode;
begin
result := FMode
end;

function TSimpleCodec.GetOnProgress: TOnEncDecProgress;
begin
result := FOnProgress
end;

function TSimpleCodec.GetSaltBytes: integer;
begin
result := FSaltBytes
end;



function TSimpleCodec.GetStreamCipher: IStreamCipher;
begin
result := FStreamCipher
end;

function TSimpleCodec.SelfTest: boolean;
begin
result := True;
// tbd
end;

procedure TSimpleCodec.SetBlockCipher( const Value: IBlockCipher);
begin
if FBlockCipher = Value then exit;
if FMode in [cmEncrypting, cmDecrypting] then
  raise Exception.Create( 'TSimpleCodec.Init - Cannot set Cipher whilst enc/decrypting.');
if FMode = cmIdle then
  Burn;
FBlockCipher := Value;
ChangedCipher
end;


procedure TSimpleCodec.SetChainMode( const Value: IBlockChainingModel);
begin
if FChainMode = Value then exit;
if FMode in [cmEncrypting, cmDecrypting] then
  raise Exception.Create( 'TSimpleCodec.Init - Cannot set Cipher whilst enc/decrypting.');
if FMode = cmIdle then
  Burn;
FChainMode := Value;
ChangedCipher
end;


procedure TSimpleCodec.SetOnProgress( Value: TOnEncDecProgress);
begin
FOnProgress := Value
end;



procedure TSimpleCodec.SetSaltBytes( Value: integer);
begin
if FSaltBytes = Value then exit;
if (Value < 0) or (Value > Max_SaltBytes) then
  raise Exception.CreateFmt( 'Maximum Salt byte count is %d', [Max_SaltBytes]);
if FMode in [cmEncrypting, cmDecrypting] then
  raise Exception.Create( 'TSimpleCodec - Cannot set SaltBytes whilst enc/decrypting.');
FSaltBytes := Value
end;


procedure TSimpleCodec.SetStreamCipher( const Value: IStreamCipher);
begin
if FStreamCipher = Value then exit;
if FMode in [cmEncrypting, cmDecrypting] then
  raise Exception.Create( 'TSimpleCodec.Init - Cannot set Cipher whilst enc/decrypting.');
if FMode = cmIdle then
  Burn;
FStreamCipher := Value;
ChangedCipher
end;

{ TCodec }

procedure TCodec.BlockCipher_ReaderProc(Reader: TReader);
begin

end;

procedure TCodec.BlockCipher_WriterProc(Writer: TWriter);
begin

end;

procedure TCodec.Burn;
begin

end;

procedure TCodec.ChainMode_ReaderProc(Reader: TReader);
begin

end;

procedure TCodec.ChainMode_WriterProc(Writer: TWriter);
begin

end;

constructor TCodec.Create(AOwner: TComponent);
begin
  inherited;

end;

procedure TCodec.DecryptAnsiString(var Plaintext: ansistring;
  const CipherText_Base64: ansistring);
begin

end;

procedure TCodec.DecryptFile(const Plaintext_FileName,
  CipherText_FileName: string);
begin

end;

procedure TCodec.DecryptMemory(
  Plaintext{out}: TStream; const CipherText{in}; CiphertextLen: integer);
begin

end;

procedure TCodec.DecryptStream(Plaintext, CipherText: TStream);
begin

end;

procedure TCodec.DecryptString(var Plaintext: string;
  const CipherText_Base64: ansistring);
begin

end;

procedure TCodec.DefineProperties(Filer: TFiler);
begin
  inherited;

end;

destructor TCodec.Destroy;
begin

  inherited;
end;

procedure TCodec.EncryptAnsiString(const Plaintext: ansistring;
  var CipherText_Base64: ansistring);
begin

end;

procedure TCodec.EncryptFile(const Plaintext_FileName,
  CipherText_FileName: string);
begin

end;

procedure TCodec.EncryptMemory(const Plaintext; PlaintextLen: integer;
  CipherText: TStream);
begin

end;

procedure TCodec.EncryptStream(Plaintext, CipherText: TStream);
begin

end;

procedure TCodec.EncryptString(const Plaintext: string;
  var CipherText_Base64: ansistring);
begin

end;

procedure TCodec.End_DecryptMemory;
begin

end;

procedure TCodec.End_EncryptMemory;
begin

end;

function TCodec.GetBlockCipher: IBlockCipher;
begin

end;

function TCodec.GetBlockCipherId: string;
begin

end;

function TCodec.GetChainMode: IBlockChainingModel;
begin

end;

function TCodec.GetChainModeId: string;
begin

end;

function TCodec.GetMode: TCodecMode;
begin

end;

function TCodec.GetOnProgress: TOnEncDecProgress;
begin

end;

function TCodec.GetSaltBytes: integer;
begin

end;

function TCodec.GetStreamCipher: IStreamCipher;
begin

end;

function TCodec.GetStreamCipherId: string;
begin

end;

procedure TCodec.Init(const Key: string);
begin

end;

procedure TCodec.Loaded;
begin
  inherited;

end;

procedure TCodec.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;

end;

procedure TCodec.Reset;
begin

end;

function TCodec.SelfTest: boolean;
begin

end;

procedure TCodec.SetBlockCipher(const Value: IBlockCipher);
begin

end;

procedure TCodec.SetBlockCipherId(const Value: string);
begin

end;

procedure TCodec.SetChainMode(const Value: IBlockChainingModel);
begin

end;

procedure TCodec.SetChainModeId(const Value: string);
begin

end;

procedure TCodec.SetLib(Value: TCryptographicLibrary);
begin

end;

procedure TCodec.SetOnProgress(Value: TOnEncDecProgress);
begin

end;

procedure TCodec.SetSaltBytes(Value: integer);
begin

end;

procedure TCodec.SetStreamCipher(const Value: IStreamCipher);
begin

end;

procedure TCodec.SetStreamCipherId(const Value: string);
begin

end;

procedure TCodec.StreamCipher_ReaderProc(Reader: TReader);
begin

end;

procedure TCodec.StreamCipher_WriterProc(Writer: TWriter);
begin

end;

{ TDesaltingStream }

constructor TDesaltingStream.Create(SaltBytes1: integer; Feeder1: TStream);
begin
FSaltBytes := SaltBytes1;
FFeeder    := Feeder1
end;

function TDesaltingStream.GetSize: int64;
begin
result := FFeeder.Size
end;

function TDesaltingStream.Read( var Buffer; Count: Integer): Longint;
begin
result := 0
end;

function TDesaltingStream.Seek( const Offset: Int64; Origin: TSeekOrigin): int64;
begin
result := FFeeder.Seek( Offset, Origin)
end;

procedure TDesaltingStream.SetSize( const NewSize: int64);
begin
FFeeder.Size := NewSize
end;

function TDesaltingStream.Write( const Buffer; Count: Integer): Longint;
var
  P: PByte;
  C: integer;
begin
result := Min( FSaltBytes, Count);
P := @Buffer;
C := Count;
if result > 0 then
  begin
  Dec( FSaltBytes, result);
  Dec( C, result);
  Inc( P, result)
  end;
if C > 0 then
  Inc( result, FFeeder.Write( P^, C))
end;

{
To Do for SBD Crypto
====================

CryptoLib Custom property
CustomHash
CustomStreamCipher
CustomBlockCipher
FindComponentReference
Codec CascadeNext/Prev
Codec Cascade Encrypt
Codec CascadeOutputStream
Codec CascadeInputStream
Codec safely set refernces to hash, streamcipher, blockcipher, chainMode
Features: Star, CryptographicallyBroken, NotImplementedYet,
          ForTestOnly, ForInternalUseOnly, 8BitMode,
          PatentBurdened, Commercial
Patent numbers:
URL:
MD5
Identify and n/i the other ciphers
BlockCipherAdapter
ECB
CBC
CFB-8bit
n/i the other hashes
Blowfish
Identify and n/i the other ciphers
design package
Study RSA theory
Study LB's implementation of big integers
Study LB's implementation of RSA
}
end.
